import { strBase64Decode, strEncodeBase64 } from '@jcstdio/jc-utils/codec'
import { ValueError } from '@jcstdio/jc-utils/exceptions'
import { isNumber, isServer } from '@jcstdio/jc-utils/is'

declare type thingType = Record<string, number>
declare type IDType = 'number' | 'string' | 'simple' | 'baseb4'

function getFs(){
  return (window  as any).electronApi.fs;
}

/**
 * @since v0.0.18
 */
class IdManager {
  /**事件容器 */
  private _things: thingType = {}
  private _STORAGE_KEY_: string = '__JC_UTILS_ID_MANAGER_STORYRA_KET__'

  /**获取 LOCAL STORAGE 键*/
  public get storageKey() {
    return this._STORAGE_KEY_
  }

  /**设置 LOCAL STORAGE 键*/
  public set storageKey(key: string) {
    this._STORAGE_KEY_ = key
  }

  /**
   * 保存到本地存储
   * - 你可以通过 getter storageKey 设置存储键。
   * @param {undefined|string} path 如果指定了此参数，且在服务端环境，则会保存到以该参数为路径的位置而非 localstorage，否则保存到localstorage
   */
  public async save(path?: string): Promise<boolean> {
    if (path && isServer()) {
      // const fs = await import('fs');
      const fs = getFs();

      const _ = {} as any
      try {
        _[this._STORAGE_KEY_] = JSON.stringify(this._things)
        fs.writeFileSync(path, JSON.stringify(_))
        return true
      } catch (e) {
        throw new Error(`${e}`)
      }
    } else {
      try {
        localStorage.setItem(this._STORAGE_KEY_, JSON.stringify(this._things))
        return Promise.resolve(true)
      } catch (e) {
        console.warn(e)
        return Promise.resolve(false)
      }
    }
  }

  /**
   * 从本地存储中加载
   * @param {undefined|string} from 如果指定了此参数且在服务端环境，则从该参数表示的路径加载数据而不是 localstorage
   * @returns 当加载成功时返回 true，否则返回 false
   */
  public async load(from?: string): Promise<boolean> {
    if (from && isServer()) {
      try {
        // const fs = await import('fs')
        const fs = getFs();
        console.log(`fs ======`, fs.default.readFileSync)

        // this._things = JSON.parse(JSON.parse(fs.readFileSync(from).toString())[this._STORAGE_KEY_]);
        return true
      } catch (e) {
        console.log(`${e}, isServer()= ${isServer()}`)

        throw new Error(`${e}, isServer()= ${isServer()}`)
      }
    } else {
      const s = localStorage.getItem(this._STORAGE_KEY_)
      if (s) {
        try {
          this._things = JSON.parse(s)
          return Promise.resolve(true)
        } catch (e) {
          console.warn(e)
          return Promise.resolve(false)
        }
      }
    }
    return Promise.resolve(false)
  }

  /**
   * 新建事物
   * @param thingName 事物名
   * @param begin id 计数起始
   * @returns 是否新建成功
   */
  public addThing(thingName: string, begin: number = 0): boolean {
    if (thingName === '') {
      throw ValueError("thingName can't be an empty string.")
    }
    if (begin < 0) {
      throw ValueError('The value of "begin" must be greater than 0.')
    }
    if (this._things[thingName]) {
      console.warn(`Thing name ${thingName} has already exists.`)
      return false
    } else {
      this._things[thingName] = begin
      return true
    }
  }

  /**
   * 返回事物是否存在
   * @param thingName 事物名
   * @since v0.0.19
   */
  public hasThing(thingName: string): boolean {
    if (this._things[thingName]) {
      return true
    }
    return false
  }

  /**
   * 删除事物
   * @param thingName 事物名
   * @returns 删除成功则返回 true，反之返回 false
   * @since v0.0.18
   */
  public dropThing(thingName: string): boolean {
    if (this._things.hasOwnProperty(thingName)) {
      delete this._things[thingName]
      return true
    } else {
      console.warn(`Thing name ${thingName} does not exists.`)
      return false
    }
  }

  /**
   * 为指定事物申请一个新 ID
   * @param thingName 事物名
   * @returns id 字符串
   */
  public getNewItemId(thingName: string, idType: IDType = 'baseb4'): string | number {
    if (this._things.hasOwnProperty(thingName)) {
      this._things[thingName] = this._things[thingName] + 1
      return this._returnUtil(thingName, this._things[thingName], idType)
    } else {
      throw ValueError(`Thing name ${thingName} does not exists.`)
    }
  }

  /**
   * 获取某个事物当前的ID
   * @param thingName 事物名
   * @returns 最后给出的一个 id
   */
  public getCurrentId(thingName: string, idType: IDType = 'baseb4'): string | number {
    if (this._things.hasOwnProperty(thingName)) {
      return this._returnUtil(thingName, this._things[thingName], idType)
    } else {
      throw ValueError(`Thing name ${thingName} does not exists.`)
    }
  }

  /**
   * 指定事件是否已有指定ID
   * @param {string} thingName 事件名
   * @param {number | string} id ID值
   * @param { IDType } idType ID类型
   * @returns { boolean } 如果有，则返回 true，否则返回 false
   */
  public hasID(
    thingName: string,
    id: number | string,
    idType: IDType = 'baseb4',
    raiseWarn: boolean = false
  ): boolean {
    const counter: number | undefined = this._things[thingName]
    if (isNumber(counter)) {
      if (isNumber(id)) {
        if (counter >= id) {
          return true
        }
      } else {
        let _idStr: string
        if (idType === 'baseb4') {
          _idStr = strBase64Decode(thingName).replace(new RegExp(`^${thingName}+-`), '')
        } else if (idType === 'simple') {
          _idStr = thingName.replace(new RegExp(`^${thingName}+-`), '')
        } else {
          _idStr = id
        }
        try {
          const idNumber: number = parseInt(_idStr)
          if (counter >= idNumber) {
            return true
          }
        } catch (e) {
          if (raiseWarn) {
            console.warn(e)
          }
          return false
        }
      }
    }
    return false
  }

  /**
   * 删除指定事件的给定ID
   * @param thingName 事件名
   * @param id ID值
   * @param idType idType ID类型
   * @param raiseWarn ID 不存在时是否抛出警告
   * @returns { boolean } 如果删除成功则返回 true，否则返回 false
   */
  // TODO: ...
  public dropID(
    thingName: string,
    id: number | string,
    idType: IDType = 'baseb4',
    raiseWarn: boolean = false
  ) {
    // const counter: number|undefined = this._things[thingName];
    // if (isNumber(counter)) {
    //   if(isNumber(id)){
    //     if(counter>=id){
    //       return true
    //     }
    //   }else{
    //     let _idStr:string;
    //     if (idType === "baseb4") {
    //       _idStr = strBase64Decode(thingName).replace(new RegExp(`^${thingName}+-`), '')
    //     } else if (idType === "simple") {
    //       _idStr = thingName.replace(new RegExp(`^${thingName}+-`), '')
    //     }else{
    //       _idStr = id
    //     }
    //     try{
    //       let idNumber: number = parseInt(_idStr)
    //       if(counter>=idNumber){
    //         return true
    //       }
    //     }catch(e){
    //       if(raiseWarn){
    //         console.warn(e);
    //       }
    //       return false
    //     }
    //   }
    // }
    // return false
  }

  /**
   * 获取某个事物当前已经给出的 id 数量
   * @param thingName 事物名
   * @returns 某个事物当前已经给出的 id 数量
   */
  public countIds(thingName: string): number {
    if (this._things.hasOwnProperty(thingName)) {
      return this._things[thingName]
    } else {
      throw ValueError(`Thing name ${thingName} does not exists.`)
    }
  }

  private _returnUtil(thingName: string, rawId: number, idType: IDType) {
    if (idType === 'number') {
      return rawId
    } else if (idType === 'string') {
      return rawId.toString()
    } else if (idType === 'simple') {
      return thingName + '-' + rawId.toString()
    } else if (idType === 'baseb4') {
      return strEncodeBase64(thingName + '-' + rawId.toString())
    } else {
      throw ValueError(`Got an unexpected id type.`)
    }
  }
}

const idManager = new IdManager()

/**获取 LOCAL STORAGE 键 */
export function getStorageKey() {
  return idManager.storageKey
}

/**
 * 设置 LOCAL STORAGE 键
 * @param key 存储键字符串
 */
export function setStorageKey(key: string) {
  if (key === '') {
    throw ValueError(`Got an empty string.`)
  }
  return (idManager.storageKey = key)
}

/**
 * 从本地存储中加载
 * @param {undefined|string} from 如果指定了此参数且在服务端环境，则从该参数表示的路径加载数据而不是 localstorage
 */
export async function load(from?: string): Promise<boolean> {
  return idManager.load(from)
}

/**
 * 保存到本地存储
 * @param path — 如果指定了此参数，且在服务端环境，则会保存到以该参数为路径的位置而非 localstorage，否则保存到localstorage
 * - 你可以通过 setStorageKey 方法设置存储键
 */
export async function save(path?: string): Promise<boolean> {
  return idManager.save(path)
}

/**
 * 新建事物
 * @param thingName 事物名
 * @param begin id 计数起始
 * @returns 是否新建成功
 */
export function addThing(thingName: string, begin: number = 0): boolean {
  return idManager.addThing(thingName, begin)
}

/**
 * 删除事物
 * @param thingName 事物名
 * @returns 删除成功则返回 true，反之返回 false
 */
export function dropThing(thingName: string): boolean {
  return idManager.dropThing(thingName)
}

/**
 * 返回事物是否存在
 * @param thingName 事物名
 * @since v0.0.19
 */
export function hasThing(thingName: string): boolean {
  return idManager.hasThing(thingName)
}

/**
 * 指定事件是否已有指定ID
 * @param {string} thingName 事件名
 * @param {number | string} id ID值
 * @param { IDType }idType ID类型
 * @returns { boolean } 如果有，则返回 true，否则返回 false
 */
export function hasID(
  thingName: string,
  id: number | string,
  idType: IDType = 'baseb4',
  raiseWarn: boolean = false
): boolean {
  return idManager.hasID(thingName, id, idType, raiseWarn)
}
/**
 * 为指定事物申请一个新 ID
 * @param thingName 事物名
 * @returns id 字符串
 */
export function getNewItemId(thingName: string, idType: IDType = 'baseb4'): string | number {
  return idManager.getNewItemId(thingName, idType)
}

/**
 * 获取某个事物当前的ID
 * @param thingName 事物名
 * @returns 最后给出的一个 id
 */
export function getCurrentId(thingName: string, idType: IDType = 'baseb4') {
  return idManager.getCurrentId(thingName, idType)
}

/**
 * 获取某个事物当前已经给出的 id 数量
 * @param thingName 事物名
 * @returns 某个事物当前已经给出的 id 数量
 */
export function countIds(thingName: string) {
  return idManager.countIds(thingName)
}
